import MD5 from "@/util/plugins/myMd5.js"
import baseUrl from '@/util/baseUrl.js'

var HttpAuth = {
    request: function (settings) {
		
        var method = settings.type ? settings.type.toUpperCase() : "GET";
		var url = settings.url;
        var async = settings.hasOwnProperty("async") ? settings.async : true;
        var username = settings.username ? settings.username : "";
        var password = settings.password ? settings.password : "";
        var urlMD5 = MD5.md5(url);

        var dataStr = "";
        if (typeof settings.data == "string") {
            dataStr = settings.data;
        } else if (typeof settings.data == "object") {
            dataStr = JSON.stringify(settings.data);
        }

        settings._method = method;
        settings._entityBody = dataStr;
        settings._wwwaKey = "HttpAuth_" + urlMD5 + "_wwwa";
        settings._ncKey = "HttpAuth_" + urlMD5 + "_nc";
        settings.headers = settings.headers || {};
		
		this._setHeader(settings);
		
		// 检查网络是否正常
		uni.getNetworkType({
		    success: (res) => {
		        if (res.networkType != 'none') {
					// #ifndef H5
					url = baseUrl + url
					// #endif
					new Promise((resolve, reject) => {
						uni.request({
							url: url,
							header: settings.headers,
							data: dataStr,
							method: method,
							success: (res) => {
								this._stateChange(res, settings);
								// resolve(res.data);
							},
							fail: (err) => {
								// reject(err);
								uni.showToast({
									title: '系统繁忙，请稍后再试',
									icon: 'none'
								})
							}
						})
					})
				} else {
					uni.showToast({ 
						title: '暂无网络，请检查是否连接网络',
						icon: 'none'
					})
				}
		    }
		});
    },
	
	//设置请求Header
    _setHeader: function (settings) {
        //Authorization
        if (settings.authType) { //需要认证
            var wwwAuthenticate = uni.getStorageSync(settings._wwwaKey);
            var authorization = "*"; //默认值无意义

            if (wwwAuthenticate && wwwAuthenticate != "null") { //能读取到，说明之前有缓存，或者是刚刚经过401并缓存了数据
                authorization = this._getAuthorization(wwwAuthenticate, settings);
            }
            settings.headers.Authorization = authorization;
        }

        //Content-Type
        if (settings.contentType) {
			settings.headers["Content-Type"] = settings.contentType;
        }

        //循环设置Header
        var headerNames = Object.getOwnPropertyNames(settings.headers);
        for (var i = 0; i < headerNames.length; i++) {
            headerNames[i] = settings.headers[headerNames[i]]
        }
    },
	
	// 请求接口成功控制
    _stateChange: function (res, settings) {
        if (res.statusCode == 401) { //服务器要求提供认证信息
            if (settings.hasOwnProperty("_auth401")) { //避免死循环
                this._log("401 auth fail", "error");
                this._log(settings);
            } else {
				// h5为：www-authenticate  Android app为：WWW-Authenticate iOSapp为：Www-Authenticate
				res.header = this._upperJSONKey(res.header); // 将json的key转成大写，不同端大小写不一致
				
                if (res.header["WWW-AUTHENTICATE"]) {
                    console.log("header:", res.header["WWW-AUTHENTICATE"]);
                }
                var wwwAuthenticate = res.header["WWW-AUTHENTICATE"];
        		console.log(res)
                uni.setStorageSync(settings._wwwaKey, wwwAuthenticate); //缓存WWW-Authenticate
                uni.setStorageSync(settings._ncKey, '0'); //nonceCount初始化
        
                this._log("401 auth", "warn");
                settings._auth401 = 1; //避免死循环
                settings.authType = this._getAuthType(wwwAuthenticate); //校正用户设定的authType
                this.request(settings);
            }
        } else {
			console.log(res)
        	settings._auth401 && this._log("401 auth ok", "warn");
        	this._log("ajax status=" + res.statusCode + ", responseText=" + res.responseText);
        	
        	if (res.statusCode == 200) {
        	
        	    if (settings.success) { //成功回调
        	        settings.context ? settings.success(res.data) : settings.success();
        	    }
        	} else {
        	    if (settings.error) { //失败回调
        	        settings.context ? settings.error(res.data) : settings.error();
        	    }
        	}
        }
    },
	
	// 考虑到 Android iOS html端 请求头的值大小写不统一 需做转换
	_upperJSONKey: function (jsonObj) {
		for (var key in jsonObj){
			jsonObj[key.toUpperCase()] = jsonObj[key];
			delete(jsonObj[key]);
		}
		return jsonObj;
	},
	
	//计算Authorization
    _getAuthorization: function (wwwAuthenticate, settings) {
        var authorization = "";

        if (settings.authType == "Basic") {
            authorization = this._getBasicAuthorization(wwwAuthenticate, settings);
        } else if (settings.authType == "Digest") {
            authorization = this._getDigestAuthorization(wwwAuthenticate, settings);
        }

        return authorization;
    },
	
	//计算Basic认证所需要的Authorization
    _getBasicAuthorization: function (wwwAuthenticate, settings) {
        //生成Authorization示例：Basic YWRtaW46MTIzNDU2

        var plain = settings.username + ":" + settings.password;
        var cipher = btoa(plain);
        this._log("plain=" + plain + ", cipher=" + cipher);

        //生成Authorization
        var authorization = "Basic " + cipher;
        return authorization;
    },

	//计算Digest认证所需要的Authorization
    _getDigestAuthorization: function (wwwAuthenticate, settings) {
        /*
        //生成Authorization示例：Digest username="xxx", realm="xxx", nonce="xxx", uri="xxx", response="xxx", opaque="xxx", qop=xxx, nc=xxx, cnonce="xxx"
        username 用户名，客户端提供，需要在服务器配置
        realm 领域，服务器产生，从401响应的WWW-Authenticate取得
        nonce 服务端随机值，服务器产生，从401响应的WWW-Authenticate取得
        uri 访问URI，客户端提供
        response 签名，客户端提供，根据指定算法计算得出，服务器会用同样算法生成后比对
        opaque 服务器产生，从401响应的WWW-Authenticate取得
        qop 保护质量，服务器产生，从401响应的WWW-Authenticate取得
        nc 计数器，客户端提供，从1开始，每次加1，格式：00000001
        cnonce 客户端随机值，客户端提供
         */
        var authObj = this._getAuthObject(wwwAuthenticate);

        //基本参数
        var authType = authObj.authType;
        var username = settings.username;
        var realm = authObj.realm;
        var nonce = authObj.nonce;
        var digestURI = this._extractUri(settings.url);
        var opaque = authObj.opaque;
        var qop = "auth";// authObj.qop;
        var nonceCount = this._getNonceCount(settings);
        var clientNonce = this._getClientNonce();

        var password = settings.password;
        var method = settings._method;
        var entityBody = settings._entityBody;
        var response, ha1, ha2, a1, a2, plain;

        //计算ha1
        a1 = username + ":" + realm + ":" + password;
        ha1 = this._md5(a1); //HA1=MD5(username:realm:password)
        this._log("a1=" + a1 + ", ha1=" + ha1);

        //计算ha2
        if (qop == "auth-int") { //qop值为"auth-int"，HA2=MD5(method:digestURI:MD5(entityBody))
            a2 = method + ":" + digestURI + ":" + this.md5(entityBody); //FIXME 如果entityBody为空如何处理？
        } else { //qop值为"auth"或未指定，HA2=MD5(method:digestURI)
            a2 = method + ":" + digestURI;
        }
        ha2 = this._md5(a2);
        this._log("a2=" + a2 + ", ha2=" + ha2);

        //计算response
        if (qop == "auth-int" || qop == "auth") { //qop值为"auth"或"auth-int"，response=MD5(HA1:nonce:nonceCount:clientNonce:qop:HA2) 
            plain = ha1 + ":" + nonce + ":" + nonceCount + ":" + clientNonce + ":" + qop + ":" + ha2;
        } else { //qop未指定，response=MD5(HA1:nonce:HA2)
            plain = ha1 + ":" + nonce + ":" + ha2;
        }
        response = this._md5(plain);
        this._log("plain=" + plain + ", response=" + response);

        //生成Authorization
        var authorization = "Digest ";
        authorization += 'username="' + username + '", '; //用户名，客户端提供，需要在服务器配置
        authorization += 'realm="' + realm + '", '; //领域，服务器产生，从401响应的WWW-Authenticate取得
        authorization += 'nonce="' + nonce + '", '; //服务端随机值，服务器产生，从401响应的WWW-Authenticate取得
        authorization += 'uri="' + digestURI + '", '; //访问URI，客户端提供
        authorization += 'response="' + response + '", '; //签名，客户端提供，根据指定算法计算得出，服务器会用同样算法生成后比对
        authorization += 'opaque="' + opaque + '", '; //服务器产生，从401响应的WWW-Authenticate取得
        authorization += 'qop=' + qop + ', '; //保护质量，服务器产生，从401响应的WWW-Authenticate取得        
        authorization += 'nc=' + nonceCount + ', '; //计数器，客户端提供，从1开始，每次加1
        authorization += 'cnonce="' + clientNonce + '"'; //客户端随机值，客户端提供
        return authorization;
    },

	//提取服务器返回的摘要认证参数
    _getAuthObject: function (wwwAuthenticate) {
        var type = this._getAuthType(wwwAuthenticate);
        var obj;

        if (type == "Digest") {
            //wwwAuthenticate示例：Digest realm="WBYX", qop="auth", nonce="1583989654942:2ab901721748c084572fde8706983c55", opaque="B2E0C5F42FA322D8104C785B59561A81"
            obj = {
                authType: type,
                realm: this._getAuthItem(wwwAuthenticate, "realm"), //WBYX
                qop: this._getAuthItem(wwwAuthenticate, "qop"), //auth
                nonce: this._getAuthItem(wwwAuthenticate, "nonce"), //1583989654942:2ab901721748c084572fde8706983c55
                opaque: this._getAuthItem(wwwAuthenticate, "opaque"), //B2E0C5F42FA322D8104C785B59561A81
                algorithm: this._getAuthItem(wwwAuthenticate, "algorithm")
            };
        } else if (type == "Basic") {
            //wwwAuthenticate示例：Basic realm="WBYX"
            obj = {
                authType: type,
                realm: this._getAuthItem(wwwAuthenticate, "realm") //WBYX
            };
        }

        return obj;
    },
	
	//获取认证类型
    _getAuthType: function (wwwAuthenticate) {
		console.log(wwwAuthenticate)
        var type = wwwAuthenticate.split(" ")[0]; //Digest或Basic
        return type;
    },

	//从qop="auth"中提取出auth
    _getAuthItem: function (str, name) {
        var arr = str.match(name + '=' + '"(.+?)"');
        //str为：Digest realm="Authenticate yourself", qop="auth", nonce="1583989654942:2ab901721748c084572fde8706983c55", opaque="B2E0C5F42FA322D8104C785B59561A81"
        //模式为：auth="(?<result>.+?)"
        //结果为["auth", auth, index: 4, input: qop="auth", groups: {result: auth}]

        var value = "";
        if (arr && arr.length == 2) {
            value = arr[1];
        }
        return value;
    },

	//从http://192.168.1.57/sddc/dataCollect提取/sddc/dataCollect
    _extractUri: function (fullURL) {
        var uri = fullURL;

        if (fullURL.substr(0, 4) == "http") { //http开头说明是绝对地址
            var searchPos = fullURL.indexOf("://") + "://".length;
            var rootPos = fullURL.indexOf("/", searchPos); //查找"http://"后第一个"/"的位置
            uri = fullURL.substring(rootPos);
        }

        return uri;
    },

	//产生clientNonce，要求随机且唯一
    _getClientNonce: function () {
        var clientNonce = "cn" + String(Date.now());
        return clientNonce;
    },

	//产生nonceCount
    _getNonceCount: function (settings) {
        var nc = Number(uni.getStorageSync(settings._ncKey)); //如果不存在则为0
        nc = nc + 1; //第一次为1，之后每次加1
        uni.setStorageSync(settings._ncKey, String(nc));

        var ncStr = String(nc);
        var len = 8 - ncStr.length;
        for (var i = 0; i < len; i++) { //将"1"转为"00000001"
            ncStr = "0" + ncStr;
        }
        return ncStr;
    },

    _md5: function (str) {
        return MD5.md5(str); //调用md5.min.js
    },

    _logSwitch: true, //日志开关
    _log: function (msg, type) {
        if (!this._logSwitch) {
            return;
        }

        if (type == "warn") {
            console.warn(msg);
        } else if (type == "error") {
            console.error(msg);
        } else {
            console.log(msg);
        }
    }
};

export default HttpAuth;
